#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include "test.h"

#define PAGE_SIZE       0x1000
#define PAGE_MASK       (~(0x1000-1))
#define PAGE_START(addr) ((addr) & PAGE_MASK)
#define PAGE_END(addr)   (PAGE_START(addr) + PAGE_SIZE)

/*  
 * hook so
 *
 *   把`libtest.so`中的malloc()函数替换成my_malloc()
 *  
 */


void *my_malloc(size_t size)
{
    printf("--ac--- %zu bytes memory are allocated by libtest.so\n", size);
    return malloc(size);
}

void hook()
{
    char       line[512];
    FILE      *fp;
    unsigned long  base_addr = 0;
    unsigned long  base_addr1 = 0;
    unsigned long  addr;
    int inode_num = 0;
    int  ret=0;

    /* (1.1) 获取`libtest.so`在进程空间中的基地址 */
    //find base address of libtest.so
    if(NULL == (fp = fopen("/proc/self/maps", "r"))) return;
    while(fgets(line, sizeof(line), fp))
    {
        if(NULL != strstr(line, "libtest.so") &&
           (ret = sscanf(line, "%"PRIxPTR"-%*lx %*4s 00000000 %*s %d", &base_addr, &inode_num)) == 2){
            printf("base_addr = 0x%lx, ret = %d \n", base_addr, ret);
            //break;
        }
        if(NULL != strstr(line, "libtest.so") &&
           sscanf(line, "%"PRIxPTR"-%*lx %*4s 00001000 %*s %d", &base_addr1, &inode_num) == 2){
            break;
        }
    }
    fclose(fp);
    printf("base_addr = 0x%lx base_addr1 = 0x%lx\n", base_addr, base_addr1);
    if(0 == base_addr) return;

    /* (1.2) 计算malloc对应的`.got.plt`表项地址 */
    //the absolute address
    addr = base_addr + 0x000000004028;
    addr = base_addr1 - 0x1000 + 0x000000004028;
    
    /* (1.3) 解除对应内存的写保护 */
    //add write permission
    mprotect((void *)PAGE_START(addr), PAGE_SIZE, PROT_READ | PROT_WRITE);

    /* (1.4) 替换`.got.plt`表项中的内容
        替换成新函数`my_malloc()`的地址
     */
    //replace the function address
    *(void **)addr = my_malloc;

    /* (1.5) 刷新cache */
    //clear instruction cache
    __builtin___clear_cache((void *)PAGE_START(addr), (void *)PAGE_END(addr));
}

int main()
{
    /* (1) hook`libtest.so`中的malloc */
    hook();

    /* (2) 调用`libtest.so`中的函数 */
    say_hello();

    while(1){
        sleep(1);
    }

    return 0;
}

#if 0

gcc hook-so.c -L. -ltest -o hook-so

export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH

./hook-so
base_addr = 0x7f8eb6198000, ret = 2 
base_addr = 0x7f8eb6199000 base_addr1 = 0x7f8eb6199000
1024 bytes memory are allocated by libtest.so
hello.

#endif

